# Import required modules
import os
import sys
import json
from pathlib import Path
from typing import List, Dict, Tuple, Any, Optional, Set

class UserSystem:
    def __init__(self, user_data_path: str):
        # Initialize user system
        self.user_data_path = Path(user_data_path)
        
        # Ensure data directory exists
        if not self.user_data_path.parent.exists():
            self.user_data_path.parent.mkdir(parents=True, exist_ok=True)
    
    def register_user(self, user) -> Tuple[bool, str]:
        # Register new user
        # Lazy import required classes to avoid circular dependencies
        from User.Student import Student
        from User.Teacher import Teacher
        from User.Manager import Manager
        
        # 1. Validate user role
        if isinstance(user, Student):
            role = "Student"
        elif isinstance(user, Teacher):
            role = "Teacher"
        elif isinstance(user, Manager):
            role = "Administrator"
        else:
            return False, "Unsupported user type"
        
        # 2. Validate English name is not empty
        if not user.EnglishName or len(user.EnglishName.strip()) == 0:
            return False, "English name cannot be empty"
        
        # 3. Check if user ID already exists
        existing_ids = self.get_existing_user_ids()
        if user.ID in existing_ids:
            return False, f"User ID {user.ID} already exists"
        
        # 4. Save user data
        try:
            self._save_user_to_json(user, role)
            return True, f"{role} user {user.ChineseName}({user.EnglishName}) registered successfully"
        except Exception as e:
            return False, f"Registration failed: {str(e)}"
    
    def register_users(self, document_path: str) -> Tuple[bool, str, List[str]]:
        # Batch register users from file
        try:
            # Read user data file
            with open(document_path, "r", encoding="utf-8") as f:
                user_data_list = json.load(f)
            
            failed_ids = []
            
            # Process users in batch
            for user_data in user_data_list:
                try:
                    # Validate required fields
                    required_fields = ["id", "password", "chinese_name", "english_name", "role"]
                    for field in required_fields:
                        if field not in user_data:
                            raise ValueError(f"Missing required field: {field}")
                    
                    # Validate English name is not empty
                    if not user_data["english_name"] or len(user_data["english_name"].strip()) == 0:
                        raise ValueError("English name cannot be empty")
                    
                    # Create user based on role
                    role = user_data["role"]
                    if role == "Student":
                        from User.Student import Student
                        user = Student(
                            ID=user_data["id"],
                            Password=user_data["password"],
                            ChineseName=user_data["chinese_name"],
                            EnglishName=user_data["english_name"],
                            Group=user_data.get("group"),
                            Courses=user_data.get("courses", [])
                        )
                    elif role == "Teacher":
                        from User.Teacher import Teacher
                        user = Teacher(
                            ID=user_data["id"],
                            Password=user_data["password"],
                            ChineseName=user_data["chinese_name"],
                            EnglishName=user_data["english_name"],
                            Courses=user_data.get("courses", [])
                        )
                    elif role == "Administrator":
                        from User.Manager import Manager
                        user = Manager(
                            ID=user_data["id"],
                            Password=user_data["password"],
                            ChineseName=user_data["chinese_name"],
                            EnglishName=user_data["english_name"]
                        )
                    else:
                        failed_ids.append(f"{user_data['id']} (invalid role: {role})")
                        continue
                    
                    # Register user
                    success, msg = self.register_user(user)
                    if not success:
                        failed_ids.append(f"{user_data['id']} ({msg})")
                        
                except KeyError as e:
                    failed_ids.append(f"{user_data.get('id', 'unknown ID')} (missing field: {str(e)})")
                except Exception as e:
                    failed_ids.append(f"{user_data.get('id', 'unknown ID')} ({str(e)})")
            
            if not failed_ids:
                return True, f"Batch registration completed, successfully registered {len(user_data_list)} users", []
            else:
                return False, f"Batch registration completed, {len(user_data_list)-len(failed_ids)} succeeded, {len(failed_ids)} failed", failed_ids
                
        except FileNotFoundError:
            return False, "User data file not found", []
        except json.JSONDecodeError:
            return False, "Invalid user data file format", []
        except Exception as e:
            return False, f"Batch registration failed: {str(e)}", []
    
    def update_user(self, user_id: str, new_chinese_name: str = None, new_english_name: str = None, 
                   new_courses: List = None, reset_password: bool = False) -> Tuple[bool, str]:
        # Update user information
        if not self.user_data_path.exists():
            return False, "User data file does not exist"
        
        try:
            # Read existing user data
            with open(self.user_data_path, "r", encoding="utf-8") as f:
                users = json.load(f)
            
            # Find user
            user_index = None
            for i, user in enumerate(users):
                if user["id"] == user_id:
                    user_index = i
                    break
            
            if user_index is None:
                return False, f"User ID {user_id} does not exist"
            
            # Update user information
            if new_chinese_name:
                users[user_index]["chinese_name"] = new_chinese_name
            if new_english_name:
                users[user_index]["english_name"] = new_english_name
            if new_courses is not None:
                users[user_index]["courses"] = new_courses
            if reset_password:
                users[user_index]["password"] = "123456"  # Default password
            
            # Save updated data
            self.save_data(users)
            return True, f"User {user_id} information updated successfully"
            
        except json.JSONDecodeError:
            return False, "Invalid user data file format"
        except Exception as e:
            return False, f"Failed to update user: {str(e)}"
    
    def delete_user(self, user_id: str) -> Tuple[bool, str]:
        # Delete user
        if not self.user_data_path.exists():
            return False, "User data file does not exist"
        
        try:
            # Read existing user data
            with open(self.user_data_path, "r", encoding="utf-8") as f:
                users = json.load(f)
            
            # Find user index
            user_index = None
            for i, user in enumerate(users):
                if user["id"] == user_id:
                    user_index = i
                    break
            
            if user_index is None:
                return False, f"User ID {user_id} does not exist"
            
            # Delete user and save
            deleted_user = users.pop(user_index)
            self.save_data(users)
            return True, f"User {user_id} ({deleted_user['chinese_name']}) has been successfully deleted"
            
        except json.JSONDecodeError:
            return False, "Invalid user data file format"
        except Exception as e:
            return False, f"Failed to delete user: {str(e)}"
    
    def get_existing_user_ids(self) -> Set[str]:
        # Get set of all existing user IDs
        if not self.user_data_path.exists():
            return set()
        
        try:
            with open(self.user_data_path, "r", encoding="utf-8") as f:
                existing_users = json.load(f)
            return {user["id"] for user in existing_users}
        except json.JSONDecodeError:
            return set()
        except Exception as e:
            print(f"Failed to get user IDs: {str(e)}")
            return set()
    
    def get_user_by_id(self, user_id: str, role_filter: List[str] = None):
        # Query user by ID
        if not self.user_data_path.exists():
            return None
        
        try:
            with open(self.user_data_path, "r", encoding="utf-8") as f:
                existing_users = json.load(f)
            
            for user_data in existing_users:
                if user_data["id"] == user_id:
                    # Role filtering
                    if role_filter and user_data["role"] not in role_filter:
                        continue
                    
                    # Create and return user object
                    return self._create_user_from_data(user_data)
            
            return None
            
        except json.JSONDecodeError:
            raise ValueError("Invalid user data file format")
    
    def get_all_users(self) -> List[Dict[str, Any]]:
        # Get all user data
        if not self.user_data_path.exists():
            return []
        
        try:
            with open(self.user_data_path, "r", encoding="utf-8") as f:
                return json.load(f)
        except json.JSONDecodeError:
            return []
        except Exception as e:
            print(f"Failed to get user list: {str(e)}")
            return []
    
    def _create_user_from_data(self, user_data: Dict[str, Any]):  
        # Create user object from data dictionary
        role = user_data["role"]
        if role == "Student": 
            from User.Student import Student
            return Student(
                ID=user_data["id"],
                Password=user_data["password"],
                ChineseName=user_data["chinese_name"],
                EnglishName=user_data["english_name"],
                Group=user_data.get("group"),
                Courses=user_data.get("courses", [])
            )
        elif role == "Teacher":
            from User.Teacher import Teacher
            return Teacher(
                ID=user_data["id"],
                Password=user_data["password"], 
                ChineseName=user_data["chinese_name"],
                EnglishName=user_data["english_name"],
                Courses=user_data.get("courses", [])
            )
        elif role == "Administrator":
            from User.Manager import Manager
            return Manager(
                ID=user_data["id"],
                Password=user_data["password"],
                ChineseName=user_data.get("chinese_name", ""), 
                EnglishName=user_data.get("english_name", "")
            )
        else:
            raise ValueError(f"Unknown user role: {role}")
    
    def _save_user_to_json(self, user, role: str):
        # Save user data to JSON file
        # Prepare user data dictionary
        user_data = {
            "id": user.ID,
            "password": user.Password,
            "chinese_name": user.ChineseName, 
            "english_name": user.EnglishName,
            "role": role
        }
        
        # Add student-specific fields
        if role == "Student" and hasattr(user, "Group"):
            user_data["group"] = user.Group
            user_data["courses"] = user.Courses
        
        # Add teacher-specific fields
        elif role == "Teacher" and hasattr(user, "Courses"):
            user_data["courses"] = user.Courses
        
        # Read existing data
        existing_users = []
        if self.user_data_path.exists(): 
            with open(self.user_data_path, "r", encoding="utf-8") as f:
                existing_users = json.load(f)
        
        # Add new user
        existing_users.append(user_data)
        
        # Save data
        self.save_data(existing_users)
    
    def save_data(self, data): 
        # Save user data to file
        with open(self.user_data_path, 'w', encoding='utf-8') as f: 
            json.dump(data, f, ensure_ascii=False, indent=4)
    
    def authenticate(self, user_id: str, password: str):
        # User authentication
        try: 
            user = self.get_user_by_id(user_id)
            if not user:
                return None, "User does not exist"
            
            if user.Password != password:
                return None, "Incorrect password"
            
            # Return user identity information
            role = ("Student" if hasattr(user, "Group") else 
                   ("Teacher" if hasattr(user, 'Courses') else 
                    "Administrator"))
            
            return user, f"Authentication successful, welcome {user.ChineseName}({user.EnglishName})"
            
        except Exception as e:
            return None, f"Authentication failed: {str(e)}"
    
    def update_student_courses(self, student_id: str, courses: List) -> Tuple[bool, str]:
        # Update student course selection information
        if not self.user_data_path.exists(): 
            return False, "User data file does not exist"
        
        try:
            # Read existing user data
            with open(self.user_data_path, 'r', encoding='utf-8') as f:
                users = json.load(f)
            
            # Find student user
            student_index = None
            for i, user in enumerate(users):
                if user["id"] == student_id and user["role"] == "Student":
                    student_index = i
                    break
            
            if student_index is None:
                return False, f"Student user with ID {student_id} not found"
            
            # Update course selection information
            users[student_index]["courses"] = courses
            
            # Save updated data
            self.save_data(users)
            return True, f"Student {student_id}'s course selection information has been updated"
            
        except json.JSONDecodeError:
            return False, "Invalid user data file format"
        except Exception as e:
            return False, f"Failed to update course selection information: {str(e)}"
        
    def remove_course_from_students(self, course_id: str) -> Tuple[bool, str, int]:
        """Remove specific course from all students' course lists"""
        if not self.user_data_path.exists():
            return False, "User data file does not exist", 0

        try:
            # Read existing user data
            with open(self.user_data_path, 'r', encoding='utf-8') as f:
                users = json.load(f)

            updated_count = 0

            # Iterate through all users and process students
            for user in users:
                if user["role"] == "Student":
                    # Check if course exists in student's course list
                    if "courses" in user and course_id in user["courses"]:
                        # Remove the course and maintain list structure
                        user["courses"] = [c for c in user["courses"] if c != course_id]
                        updated_count += 1

            if updated_count > 0:
                # Save updated data if any changes were made
                self.save_data(users)
                return True, f"Successfully removed course {course_id} from {updated_count} students", updated_count
            else:
                return True, f"No students found enrolled in course {course_id}", 0

        except json.JSONDecodeError:
            return False, "Invalid user data file format", 0
        except Exception as e:
            return False, f"Failed to remove course: {str(e)}", 0